var LLParser = require('./LLParser');
var TAG_TYPES = require('./StringEscape').TAG_TYPES;
var globalOptions = require('./globalOptions');
var o = {
    amp: '&',
    gt: '>',
    lt: '<',
    nbsp: ' ',
    quot: '"',
    apos: '\''
};
var s = ' \n\r\t\f';
var l = /^[ \n\r\t\f]+|[ \n\r\t\f]+$/g;
var d = {};
[
    'area',
    'base',
    'br',
    'col',
    'embed',
    'hr',
    'img',
    'input',
    'link',
    'meta',
    'param',
    'source',
    'track',
    'wbr'
].forEach(function (e) {
    d[e] = true;
});
var A = globalOptions.hasDOMBackend ? document.createElement('div') : null;
var decodeEntities = function (e) {
    return e.replace(/&(([a-zA-Z]+)|(#x{0,1}[\da-zA-Z]+));/gi, function (e, t) {
        return o[t] ? o[t] : /^#[0-9]{1,4}$/.test(t) ? String.fromCharCode(t.slice(1)) : /^#x[0-9a-f]{1,4}$/i.test(t) ? String.fromCharCode('0' + t.slice(1)) : globalOptions.hasDOMBackend ? function (e) {
            return A ? (A.innerHTML = e, A.innerText || A.textContent) : e;
        }(e) : e;
    });
};
var h = null;
var u = null;
var p = function (e) {
    return LLParser.create({
        HTML: [
            {
                id: 'tag',
                states: [
                    'HTML',
                    'TAG'
                ]
            },
            {
                id: 'text',
                states: [
                    'HTML',
                    'TEXT'
                ]
            },
            {
                id: 'tag1',
                states: ['TAG']
            },
            {
                id: 'text1',
                states: ['TEXT']
            },
            {
                id: '_null',
                states: ['NULL'],
                overwrite: true
            }
        ],
        TEXT: [
            {
                id: '_raw',
                states: [
                    'TEXT',
                    '^<'
                ]
            },
            {
                id: '_jump',
                states: ['^<']
            },
            {
                id: '_jump',
                states: ['NULL']
            }
        ],
        TAG: [{
                id: '_blank',
                states: [
                    '<',
                    'TAG_START'
                ]
            }],
        TAG_END: [
            {
                id: '_blankConcat',
                states: [
                    '/',
                    'TAG_END_NAME',
                    '>'
                ]
            },
            {
                id: '_jump',
                states: ['>']
            }
        ],
        TAG_START: [
            {
                id: 'comment',
                states: [
                    '!',
                    '-',
                    '-',
                    'COMMENT_CONTENT'
                ]
            },
            {
                id: 'endTag',
                states: [
                    '/',
                    'TAG_END_NAME',
                    '>'
                ]
            },
            {
                id: 'startTag',
                states: [
                    'TAG_START_NAME',
                    'ATTRS',
                    'TAG_END'
                ]
            },
            {
                id: '_blank',
                states: [
                    s,
                    'TAG_START'
                ]
            }
        ],
        TAG_START_NAME: [
            {
                id: '_raw',
                states: [
                    'TAG_START_NAME',
                    '^>/ \n\r\t\f'
                ]
            },
            {
                id: '_jump',
                states: ['^>/ \n\r\t\f']
            }
        ],
        TAG_END_NAME: [
            {
                id: '_raw',
                states: [
                    'TAG_END_NAME',
                    '^>'
                ]
            },
            {
                id: '_jump',
                states: ['^>']
            },
            {
                id: '_jump',
                states: ['NULL']
            }
        ],
        ATTRS: [
            {
                id: '_blank',
                states: [
                    s,
                    'ATTRS'
                ]
            },
            {
                id: '_jump',
                states: [
                    'ATTRS',
                    s
                ]
            },
            {
                id: 'attrs',
                states: [
                    'ATTR',
                    'ATTRS'
                ]
            },
            {
                id: '_null',
                states: ['NULL'],
                overwrite: true
            }
        ],
        ATTR: [{
                id: 'attr',
                states: [
                    'ATTR_NAME',
                    'ATTR_NAME_AFTER'
                ]
            }],
        ATTR_NAME: [
            {
                id: '_raw',
                states: [
                    'ATTR_NAME',
                    '^=>/ \n\r\t\f'
                ]
            },
            {
                id: '_jump',
                states: ['^=>/ \n\r\t\f']
            }
        ],
        ATTR_NAME_AFTER: [
            {
                id: '_blank',
                states: [
                    s,
                    'ATTR_NAME_AFTER'
                ]
            },
            {
                id: '_blank',
                states: [
                    '=',
                    'ATTR_VALUE'
                ]
            },
            {
                id: '_empty',
                states: ['NULL']
            }
        ],
        ATTR_VALUE: [
            {
                id: '_blank',
                states: [
                    s,
                    'ATTR_VALUE'
                ]
            },
            {
                id: '_blank',
                states: [
                    '"',
                    'ATTR_VALUE_INNER_1',
                    '"'
                ]
            },
            {
                id: '_blank',
                states: [
                    '\'',
                    'ATTR_VALUE_INNER_2',
                    '\''
                ]
            },
            {
                id: '_jump',
                states: ['ATTR_VALUE_INNER_3']
            },
            {
                id: '_empty',
                states: ['NULL']
            }
        ],
        ATTR_VALUE_INNER_1: [
            {
                id: '_raw',
                states: [
                    'ATTR_VALUE_INNER_1',
                    '^"'
                ]
            },
            {
                id: '_jump',
                states: ['^"']
            },
            {
                id: '_jump',
                states: ['NULL']
            }
        ],
        ATTR_VALUE_INNER_2: [
            {
                id: '_raw',
                states: [
                    'ATTR_VALUE_INNER_2',
                    '^\''
                ]
            },
            {
                id: '_jump',
                states: ['^\'']
            },
            {
                id: '_jump',
                states: ['NULL']
            }
        ],
        ATTR_VALUE_INNER_3: [
            {
                id: '_raw',
                states: [
                    'ATTR_VALUE_INNER_3',
                    '^> \n\r\t\f'
                ]
            },
            {
                id: '_jump',
                states: ['^> \n\r\t\f']
            },
            {
                id: '_jump',
                states: ['NULL']
            }
        ],
        COMMENT_CONTENT: [
            {
                id: '_concat',
                states: [
                    'ALL',
                    'COMMENT_CONTENT'
                ]
            },
            {
                id: '_concat',
                states: [
                    '-',
                    'COMMENT_CONTENT_DASH_1'
                ]
            }
        ],
        COMMENT_CONTENT_DASH_1: [
            {
                id: '_concat',
                states: [
                    'ALL',
                    'COMMENT_CONTENT'
                ]
            },
            {
                id: '_concat',
                states: [
                    '-',
                    'COMMENT_CONTENT_DASH_2'
                ]
            }
        ],
        COMMENT_CONTENT_DASH_2: [
            {
                id: '_concat',
                states: [
                    'ALL',
                    'COMMENT_CONTENT'
                ]
            },
            {
                id: '_concat',
                states: [
                    '-',
                    'COMMENT_CONTENT_DASH_2'
                ]
            },
            {
                id: '_jump',
                states: ['>']
            }
        ]
    }, {
        _null: function () {
        },
        _empty: function () {
            return '';
        },
        _jump: function (e) {
            return e[0];
        },
        _raw: function (e) {
            return e[0] + e[1];
        },
        _concat: function (e) {
            return e[0] + e[1];
        },
        _blankConcat: function (e) {
            return e[0] + e[2];
        },
        _blank: function (e) {
            return e[1];
        },
        attr: function (e) {
            return [{
                    n: e[0],
                    v: decodeEntities(e[1])
                }];
        },
        attrs: function (e) {
            return e[1] ? e[0].concat(e[1]) : e[0];
        },
        startTag: function (e) {
            var t = e[0].toLowerCase();
            return {
                t: TAG_TYPES.TAG_START,
                n: t,
                a: e[1] || [],
                selfClose: '/>' === e[2] || d[t]
            };
        },
        endTag: function (e) {
            return {
                t: TAG_TYPES.TAG_END,
                n: e[1].toLowerCase()
            };
        },
        comment: function (e) {
            return {
                t: TAG_TYPES.COMMENT,
                c: e[3].slice(0, -3)
            };
        },
        tag1: function (e) {
            return [e[0]];
        },
        text1: function (e) {
            return [{
                    t: TAG_TYPES.TEXT,
                    c: e[0]
                }];
        },
        tag: function (e) {
            e[0].push(e[1]);
            return e[0];
        },
        text: function (e) {
            var t = e[0];
            t[t.length - 1].t === TAG_TYPES.TEXT ? t[t.length - 1].c += e[1] : t.push({
                t: TAG_TYPES.TEXT,
                c: e[1]
            });
            return t;
        }
    }, e);
};
exports.TAG_TYPES = TAG_TYPES;
exports.decodeEntities = decodeEntities;
exports.parse = function (e, t) {
    var i = null;
    if (e.length <= 65536) {
        h || (h = p(65536));
        i = h;
    } else {
        u || (u = p(1048576));
        i = u;
    }
    var n = function (e, t) {
        var i = { c: [] };
        var n = i;
        var r = [];
        var o = null;
        for (var s = 0; s < e.length; s++) {
            var d = e[s];
            if (d.t === TAG_TYPES.TAG_START) {
                o = {
                    t: TAG_TYPES.TAG_START,
                    n: d.n,
                    a: d.a,
                    c: []
                };
                n.c.push(o);
                if (!d.selfClose) {
                    r.push(n);
                    n = o;
                };
            } else if (d.t === TAG_TYPES.TAG_END) {
                var A = r.length - 1;
                var h = true;
                for (o = n; d.n !== o.n;)
                    if (!(o = r[A--])) {
                        h = false;
                        break;
                    }
                if (h)
                    for (; r.length > A;)
                        n = r.pop();
            } else
                d.t === TAG_TYPES.TEXT && (d.c = decodeEntities(t ? d.c : d.c.replace(l, '')), d.c && n.c.push(d));
        }
        return i;
    }(i.parse('HTML', e) || [], t);
    return n.c;
};
